﻿

using System.Threading;
using System.Diagnostics;
using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Security.Cryptography;

namespace ttDuplicateManager
{
    public partial class ttMain : Form
    {
        public ttMain()
        {
            InitializeComponent();
        }
        FolderBrowserDialog duplicatesFolder;
        string selectedFolder = "";
        List<string> allFiles = new List<string>();
        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            duplicatesFolder = new FolderBrowserDialog();
            DialogResult diagRes=  duplicatesFolder.ShowDialog();
            switch (diagRes)
            { 
                case System.Windows.Forms.DialogResult.OK:
                    selectedFolder = duplicatesFolder.SelectedPath;
                    strExtension = txtExtension.Text; 
                    lblStatus.Text = "Search folder selected: " + selectedFolder;
                    
                    theList.Clear();
                    duplicateList.Clear();

                    duplicateFinder = new Thread(new ThreadStart(duplicateFinderThreadbody));
                    duplicateFinder.Start();
                    break;
                default:
                    selectedFolder = "";
                    break;
            }

        }
        Thread duplicateFinder;
    


        List<fileNameHashPair> theList = new List<fileNameHashPair>();
        List<fileNameHashPair> duplicateList = new List<fileNameHashPair>();

        string strExtension = "";

        public string getfilenamefromfullpath(string path)
        {
            int lastIndexOfWhack =path.LastIndexOf("\\");
            return path.Substring(lastIndexOfWhack, path.Length - lastIndexOfWhack);
        }

        public string getfilepathfromfullpath(string path)
        {
            return path.Substring(0, path.LastIndexOf("\\"));
        }

        void duplicateFinderThreadbody()
        {
            try
            {
                string[] files = Directory.GetFiles(selectedFolder, strExtension, SearchOption.AllDirectories);

                Invoke(new dlgsetMax(setMax), new object[] { files.Count() });
                int counter = 0;
                foreach (string file in files)
                {

                    fileNameHashPair item = new fileNameHashPair();
                    item.md5Hash = convertHashToString(GetMD5OfFile(file));
                    item.filenameWpath = file;
                    item.filename = getfilenamefromfullpath(file);
                    item.filepath = getfilepathfromfullpath(file);

                    theList.Add(item);
                    Debug.WriteLine(item.md5Hash + item.filename + item.filenameWpath + item.filepath);

                    Invoke(new dlgsetProgress(setProgress), new object[] { counter });
                    counter++;

                }

                var query = (from file in theList
                             group file by file.md5Hash into groupedFile
                             select new { md5Key = groupedFile.Key, fileCount = groupedFile.Count() });

                DataTable tableOfDuplicates = new DataTable();
                DataColumn dcFilename = new DataColumn("dcFilename");
                DataColumn dcFilepath = new DataColumn("dcFilepath");
                DataColumn dcFilecount = new DataColumn("dcFilecount");
                tableOfDuplicates.Columns.Add(dcFilename);
                tableOfDuplicates.Columns.Add(dcFilepath);
                tableOfDuplicates.Columns.Add(dcFilecount);

                foreach (var ss in query)
                {
                    var f = ss;
                    if (f.fileCount > 1)
                    {
                        //the file is a duplicate
                        DataRow drDuplicate = tableOfDuplicates.NewRow();
                        fileNameHashPair fileRecord = (from fDup in theList
                                                       where fDup.md5Hash == f.md5Key
                                                       select fDup).First();
                        drDuplicate["dcFilename"] = fileRecord.filename;
                        var pathsQuery = (from filePath in theList
                                          where filePath.md5Hash == f.md5Key
                                          select filePath.filepath).ToArray<string>();
                        StringBuilder pathsBuilder = new StringBuilder();
                        foreach (var filepath in pathsQuery)
                        {
                            pathsBuilder.AppendLine(filepath);
                        }
                        drDuplicate["dcFilepath"] = pathsBuilder.ToString();
                        drDuplicate["dcFileCount"] = f.fileCount.ToString();
                        tableOfDuplicates.Rows.Add(drDuplicate);
                        duplicateList.Add(fileRecord);
                    }
                }
                Invoke(new dSetDataSource(setDataSourceDataGrid), new object[] { tableOfDuplicates });

                Invoke(new dlgsetComplete(setComplete));
            }
            catch (Exception err)
            {
                MessageBox.Show(err.ToString());
            }
        }
        

        private MD5 GetMD5OfFile(string file)
        {
            FileStream fs = System.IO.File.OpenRead(file);
            MD5 md5 = new MD5CryptoServiceProvider();
            BinaryReader bReader = new BinaryReader(fs);
            byte[] buffer = bReader.ReadBytes((int)fs.Length);
            byte[] retVal = md5.ComputeHash(buffer);
            fs.Close();
            
            return md5;
        }

        delegate void dlgAddNode(TreeNode node);
        void AddNode(TreeNode node)
        { }

        delegate void dlgUpdateLblStatus(string message);
        void UpdateLblStatus(string message)
        {
            lblStatus.Text = message;
            

        }

        delegate void dSetDataSource(DataTable ds);
        public void setDataSourceDataGrid(DataTable ds)
        {
            dgDuplicates.DataSource = ds;
            dgDuplicates.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells; 

        }
        delegate void dlgsetMax(int valueMax);
        delegate void dlgsetProgress(int value);
        delegate void dlgsetComplete();

        void setMax(int valueMax)
        {
            bar.Maximum = valueMax;
        }
        void setProgress(int value)
        {
            bar.Value = value;
        }
        void setComplete()
        {
            bar.Value = bar.Maximum;
            
        }

        string convertHashToString(MD5 hashToConvert)
        {
            StringBuilder sbr = new StringBuilder();

            foreach (byte b in hashToConvert.Hash)
            {
                sbr.Append(b.ToString("X2"));
            }

            return sbr.ToString();
                
                
        }

        private void btnDeleteDuplicates_Click(object sender, EventArgs e)
        {
            foreach (var fileRecord in duplicateList)
            {
                var duplicateSet = (from file in theList
                                    where file.md5Hash == fileRecord.md5Hash
                                    select file).ToArray<fileNameHashPair>();
                for (int i = 1; i < duplicateSet.Count(); i++)
                {
                    File.Delete(duplicateSet[i].filenameWpath);
                }
            }
        }

        private void pictureBox1_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("explorer.exe", "http://www.techytube.com");
        }

        private void toolStripDropDownButton1_Click(object sender, EventArgs e)
        {

        }

        private void btnMoveDuplicates_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folderDialog = new FolderBrowserDialog();
            DialogResult result= folderDialog.ShowDialog();
            if (result == System.Windows.Forms.DialogResult.OK)
            {
                foreach (var fileRecord in duplicateList)
                {
                    var duplicateSet = (from file in theList
                                        where file.md5Hash == fileRecord.md5Hash
                                        select file).ToArray<fileNameHashPair>();
                    for (int i = 1; i < duplicateSet.Count(); i++)
                    {
                        File.Move(duplicateSet[i].filenameWpath, folderDialog.SelectedPath + "\\DuplicateMoved_" + duplicateSet[i].filename);
                    }
                }
            }
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("explorer.exe", "http://www.techytube.com");
        }

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            foreach (var fileRecord in duplicateList)
            {
                var duplicateSet = (from file in theList
                                    where file.md5Hash == fileRecord.md5Hash
                                    select file).ToArray<fileNameHashPair>();
                for (int i = 1; i < duplicateSet.Count(); i++)
                {
                    File.Copy(duplicateSet[i].filenameWpath, duplicateSet[i].filenameWpath + ".RenamedDuplicate");
                    File.Delete(duplicateSet[i].filenameWpath);
                }
            }
        }
    }
}
